/**
 * @file      : icm20608.c
 * @author    : huenrong (huenrong1028@gmail.com)
 * @date      : 2020-05-27 19:34:00
 *
 * @copyright : Copyright (c) 2020  胡恩荣
 *
 */

#include "icm20608.h"

/**
 * @brief  icm20608传感器初始化
 * @return 成功: 返回设备文件描述符
 *         失败: -1
 */
int icm20608_init(void)
{
    int ret = -1;
    int fd = -1;

    // 打开设备
    fd = spi_open(ICM20608_DEV_PATH, SPI_MODE_0);
    if (-1 == fd)
    {
        perror("spi open fail");

        return -1;
    }

    // 导出片选脚
    ret = gpio_export(GPIO_ICM20608_CS);
    if (0 != ret)
    {
        perror("icm20608 export cs pin fail");

        return -1;
    }

    // 设置片选脚方向
    ret = gpio_set_direction(GPIO_ICM20608_CS, GPIO_OUT);
    if (0 != ret)
    {
        perror("icm20608 set cs direction fail");

        return -1;
    }

    // 设置片选脚电平
    // ret = gpio_set_value(GPIO_ICM20608_CS, GPIO_HIGH);
    ret = gpio_set_value(GPIO_ICM20608_CS, GPIO_LOW);
    if (0 != ret)
    {
        perror("icm20608 set cs value fail");

        return -1;
    }

    // 寄存器初始化
    // 重置内部寄存器, 并恢复默认设置
    ICM20608_CS_L();
    ret = spi_write_byte(fd, (ICM20_PWR_MGMT_1 & 0x7F), 0x80);
    if (0 != ret)
    {
        perror("icm20608 set default fail\n");

        return -1;
    }
    ICM20608_CS_H();
    usleep(50 * 1000);

    // 自动选择最佳的可用时钟源–PLL(如果已准备好), 否则使用内部振荡器
    ICM20608_CS_L();
    ret = spi_write_byte(fd, (ICM20_PWR_MGMT_1 & 0x7F), 0x01);
    if (0 != ret)
    {
        return -1;
    }
    ICM20608_CS_H();
    usleep(50 * 1000);

    // 输出速率是内部采样率
    ICM20608_CS_L();
    ret = spi_write_byte(fd, (ICM20_SMPLRT_DIV & 0x7F), 0x00);
    ICM20608_CS_H();
    if (0 != ret)
    {
        return -1;
    }

    // 陀螺仪±2000dps量程
    ICM20608_CS_L();
    ret = spi_write_byte(fd, (ICM20_GYRO_CONFIG & 0x7F), 0x18);
    ICM20608_CS_H();
    if (0 != ret)
    {
        return -1;
    }

    // 加速度计±16G量程
    ICM20608_CS_L();
    ret = spi_write_byte(fd, (ICM20_ACCEL_CONFIG & 0x7F), 0x18);
    ICM20608_CS_H();
    if (0 != ret)
    {
        return -1;
    }

    // 陀螺仪低通滤波BW=20Hz
    ICM20608_CS_L();
    ret = spi_write_byte(fd, (ICM20_CONFIG & 0x7F), 0x04);
    ICM20608_CS_H();
    if (0 != ret)
    {
        return -1;
    }

    // 加速度计低通滤波BW=21.2Hz
    ICM20608_CS_L();
    ret = spi_write_byte(fd, (ICM20_ACCEL_CONFIG2 & 0x7F), 0x04);
    ICM20608_CS_H();
    if (0 != ret)
    {
        return -1;
    }

    // 打开加速度计和陀螺仪所有轴
    ICM20608_CS_L();
    ret = spi_write_byte(fd, (ICM20_PWR_MGMT_2 & 0x7F), 0x00);
    ICM20608_CS_H();
    if (0 != ret)
    {
        return -1;
    }

    // 关闭低功耗
    ICM20608_CS_L();
    ret = spi_write_byte(fd, (ICM20_LP_MODE_CFG & 0x7F), 0x00);
    ICM20608_CS_H();
    if (0 != ret)
    {
        return -1;
    }

    // 关闭FIFO
    ICM20608_CS_L();
    ret = spi_write_byte(fd, (ICM20_FIFO_EN & 0x7F), 0x00);
    ICM20608_CS_H();
    if (0 != ret)
    {
        return -1;
    }

    return fd;
}

/**
 * @brief  关闭设备
 * @param  fd: 设备文件描述符
 * @return 成功: 0
 *         失败: -1
 */
int icm20608_close(const int fd)
{
    int ret = -1;

    ret = spi_close(fd);

    return ret;
}

/**
 * @brief  icm20608读取设备id
 * @param  read_id: 读取到的设备id
 * @param  fd: 设备文件描述符
 * @return 成功: 0
 *         失败: -1
 */
int icm20608_read_id(uint8_t *read_id, const int fd)
{
    int ret = -1;

    // 读取设备id
    ICM20608_CS_L();
    ret = spi_read_byte(read_id, fd, (ICM20_WHO_AM_I | 0x80));
    ICM20608_CS_H();
    // 读取失败
    if (0 != ret)
    {
        return -1;
    }

    return 0;
}

/**
 * @brief  icm20608读取加速度值
 * @param  read_accel_x: 加速度x轴原始数据
 * @param  read_accel_y: 加速度y轴原始数据
 * @param  read_accel_z: 加速度z轴原始数据
 * @param  fd: 设备文件描述符
 * @return 成功: 0
 *         失败: -1
 */
int icm20608_read_accel(short *read_accel_x, short *read_accel_y, short *read_accel_z, const int fd)
{
    int ret = -1;
    uint8_t read_data[6] = {0};

    // 读取加速度数据
    ICM20608_CS_L();
    ret = spi_read_nbyte(read_data, fd, (ICM20_ACCEL_XOUT_H | 0x80), 6);
    ICM20608_CS_H();
    // 读取失败
    if (0 != ret)
    {
        return -1;
    }

    *read_accel_x = (short)((read_data[0] << 8) | read_data[1]);
    *read_accel_y = (short)((read_data[2] << 8) | read_data[3]);
    *read_accel_z = (short)((read_data[4] << 8) | read_data[5]);

    return 0;
}

/**
 * @brief  icm20608读取温度值
 * @param  read_temp: 温度原始值
 * @param  fd: 设备文件描述符
 * @return 成功: 0
 *         失败: -1
 */
int icm20608_read_temp(short *read_temp, const int fd)
{
    int ret = -1;
    uint8_t read_data[2] = {0};

    // 读取温度
    ICM20608_CS_L();
    ret = spi_read_nbyte(read_data, fd, (ICM20_TEMP_OUT_H | 0x80), 2);
    ICM20608_CS_H();
    // 读取失败
    if (0 != ret)
    {
        return -1;
    }

    *read_temp = (short)((read_data[0] << 8) | read_data[1]);

    return 0;
}

/**
 * @brief  icm20608读取陀螺仪值
 * @param  read_gyro_x: 陀螺仪x轴原始数据
 * @param  read_gyro_y: 陀螺仪y轴原始数据
 * @param  read_gyro_z: 陀螺仪z轴原始数据
 * @param  fd: 设备文件描述符
 * @return 成功: 0
 *         失败: -1
 */
int icm20608_read_gyro(short *read_gyro_x, short *read_gyro_y, short *read_gyro_z, const int fd)
{
    int ret = -1;
    uint8_t read_data[6] = {0};

    // 读取陀螺仪数据
    ICM20608_CS_L();
    ret = spi_read_nbyte(read_data, fd, (ICM20_GYRO_XOUT_H | 0x80), 6);
    ICM20608_CS_H();
    // 读取失败
    if (0 != ret)
    {
        return -1;
    }

    *read_gyro_x = (short)((read_data[0] << 8) | read_data[1]);
    *read_gyro_y = (short)((read_data[2] << 8) | read_data[3]);
    *read_gyro_z = (short)((read_data[4] << 8) | read_data[5]);

    return 0;
}
